package com.fsbm.ctech.maxis.ebpsbackend;

import com.checkfree.isolutions.customer.persist.*;
import com.checkfree.isolutions.persist.*;
import com.checkfree.isolutions.statement.*;
import com.checkfree.isolutions.statement.persist.*;
import com.checkfree.isolutions.utility.*;
import com.checkfree.isolutions.admin.*;
import com.checkfree.isolutions.streaming.*;
import com.checkfree.isolutions.admin.ObjectId;

import java.io.File;
import java.io.FileOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Vector;
import java.util.Properties;

import java.io.*;
import java.text.*;
import java.util.*;
import java.util.Date;
import java.sql.*;

import com.lowagie.text.Document;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfWriter;

/**
 *
 */

public class BillReprintDeliver {
  static ConfigObject cfgObj = new ConfigObject();
  static int intFileSize = cfgObj.maxFileAmount;
  static int maxThread = 1;
  static String APP_NAME = "BillReprintDeliver";
  static String NORMAL = "N";
  static String COURIER = "C";

  public static void main(String argv[]) {
    String strMaxThread="";
    for (int optind = 0; optind < argv.length; optind++) {
      if (argv[optind].toLowerCase().indexOf("-threadcount") != -1) {
        strMaxThread = argv[optind];
        strMaxThread = strMaxThread.substring(strMaxThread.indexOf("=")+1);
        maxThread = Integer.parseInt(strMaxThread);
      } else if (argv[optind].toLowerCase().startsWith("-h")) {
        printUsage();
        System.exit(1);
      } else {
        break;
      }
    }
    // Main Program Call
    startMain();
    System.exit(0);
  }

  // Start of sub-routines
  public static void startMain() {
    java.util.Date startTime = new Date();
    java.util.Date startTransferTime = new Date();
    java.util.Date endTransferTime = new Date();

    // Start to call creation of CSV, PDF and zipping of files
    try{
      runner(NORMAL);
      runner(COURIER);

      //  Start of Transfer Functionality
      java.util.Date endTime = new Date();

      // Display start and end times of Execution
      cfgObj.write("\n-------------------------------------------------" +
                   "\nStart of Execution : " + startTime +
                   "\nEnd   of Execution : " + endTime, APP_NAME);

    } catch (Exception ex) {
      cfgObj.write("Process Name(startMain)- " + ex.getClass() + " " + ex.getMessage(), APP_NAME);
    }
  }


  // Start of runner sub-routines
  public static void runner(String mailMethod) {
    try{

      Vector vecStatementIds = new Vector();
      Vector vecThreads = new Vector();
      Vector vecRunningThreads = new Vector();

      String[] strBillReprintArrayFileName = new String[intFileSize];

      // Retrieve the statement IDs from custlog table
      vecStatementIds = GetBillReprint.retrieveStatementIds(mailMethod);

      if(vecStatementIds.size() > 0){

        // Split all the statement IDs in to several files
        Vector vecSplitStatementIds = GetStatement.splitStatementIds(vecStatementIds, APP_NAME + mailMethod);

        if (mailMethod.equals(NORMAL)){
          cfgObj.write("\nRunning Bill Reprint processes (NORMAL)...", APP_NAME);
        } else{
          cfgObj.write("\nRunning Bill Reprint processes (COURIER)...", APP_NAME);
        }

        int vSize = vecSplitStatementIds.size();

        if (vSize > 0){
          cfgObj.write("Creating files...", APP_NAME);

          for(int i =0;i < vSize; i++){
            SplitStatementIdsDataBean dataBean = (SplitStatementIdsDataBean)vecSplitStatementIds.elementAt(i);
            strBillReprintArrayFileName[i] = dataBean.getStrFileName();
            BillReprintThread thread = new BillReprintThread(vecStatementIds,dataBean);
            vecThreads.addElement(thread);
          }

          while(true){
            if(vecThreads.size()<=0 && vecRunningThreads.size()<=0) break;

            for(int j=0;j<vecRunningThreads.size();j++){
              BillReprintThread runningThread = (BillReprintThread)vecRunningThreads.elementAt(j);

              if (runningThread.isAlive() == false){
                vecRunningThreads.removeElementAt(j);
              }
            }

            if ((vecRunningThreads.size() < maxThread ) && (vecThreads.size() > 0)){
              BillReprintThread thread = (BillReprintThread)vecThreads.firstElement();
              thread.start();
              vecRunningThreads.addElement(thread);
              vecThreads.removeElement(thread);
            }

            try{
              Thread.sleep(1000);
            }catch(InterruptedException ie){
              System.out.println("Exception is....."+ie);
            }
          }// end while

          cfgObj.write("Initialize Packaging...", APP_NAME);
          PrepareFiles.PackageBillReprintDeliveryFiles(strBillReprintArrayFileName, mailMethod);
        }// end if
      } else{
        if (mailMethod.equals(NORMAL)){
          cfgObj.write("Process Name(runner) - There are no Statements found for Bill Reprint (NORMAL).",APP_NAME);
        } else{
          cfgObj.write("Process Name(runner) - There are no Statements found for Bill Reprint (COURIER).",APP_NAME);
        }
      }// end if
    }catch (Exception ex) {
      cfgObj.write("Process Name(runner)- " + ex.getClass() + " " + ex.getMessage(),APP_NAME);
    }//end try
  }// end

  // BillReprintThread Thread class
  public static class BillReprintThread extends Thread {
    Vector vecStmtIds = new Vector();
    SplitStatementIdsDataBean dataBean = new SplitStatementIdsDataBean();

    BillReprintThread(Vector stmtIds,SplitStatementIdsDataBean splitDataBean) {
      this.vecStmtIds = stmtIds;
      this.dataBean = splitDataBean;
    }

    public void run() {

      FileOutputStream outstr = null;
      InputStream instr   = null;
      int intCommitCtr = 0;
      boolean boolFirstLine = true;

      int intStartIdx = dataBean.getIntStartIdx();
      int intEndIdx = dataBean.getIntEndIdx();
      String strFileName = dataBean.getStrFileName();

      try{
        PersistServer.activate();
        cfgObj.write("Activating Persistent Server.....",APP_NAME);

        FileWriter fwFile = null;
        fwFile = new FileWriter(strFileName+".csv",true);

        int persisServerCtr = 0;
        int pos = strFileName.lastIndexOf("/");
        int totalPageCount = 0;

        for(int i=intStartIdx;i<intEndIdx;i++){
          String strTemp = (String)vecStmtIds.elementAt(i);

          String strStmtId  = strTemp.substring(0, strTemp.indexOf("~"));      // format is stmtID~emailaddr
          String strActivityId  = strTemp.substring(strStmtId.length()+1);

          if(persisServerCtr == 0) {
            PersistServer.beginTransaction();
            cfgObj.write("Starting the transaction.....",APP_NAME);
          }

          StatementHome home = StatementHomeImpl.singleton();
          AccountHome acctHome = AccountHomeImpl.singleton();

          int statementId = Integer.parseInt(strStmtId.trim());
          ObjectId objectId = new ObjectId(IClassId.STATEMENT, statementId);
          com.checkfree.isolutions.statement.persist.Statement cfiStatement = home.findById(objectId);

          // extract to string the ffg info for a clearer view
          Account accountObj = acctHome.findById(cfiStatement.getAccountId());
          String acctId = accountObj.getExternalKey();
          String billingPeriod = new SimpleDateFormat("dd/MM/yyyy").format(cfiStatement.getDate());

          if(boolFirstLine){
            fwFile.write(cfgObj.reprintTitle + " (" + new SimpleDateFormat("dd/MM/yyyy hh:mm").format(new Date()) + ")\n");
            fwFile.write(cfgObj.reprintHeader1 + "," + cfgObj.reprintHeader2 + "," + cfgObj.reprintHeader3 + "," + cfgObj.reprintHeader4);
            boolFirstLine = false;
          }

          String appendToFileName = "." + statementId + "~" + acctId + ".pdf";
          String fullPathFileName = strFileName + appendToFileName;
          String fileName = strFileName.substring(pos+1) + appendToFileName;

          outstr        = new FileOutputStream(fullPathFileName);
          byte[] buffer = new byte[262144];
          int size      = 0;
          instr         = cfiStatement.getExternalFormatData(); // actual downloading of file in pdf

          persisServerCtr++;

          if(persisServerCtr == 100) {
            // close transaction to avoid wasting memory
            PersistServer.commitTransaction();
            //cfgObj.write("Commiting transaction when ctr =100.......", APP_NAME);
            persisServerCtr = 0;
          }

          while ((size  = instr.read(buffer, 0, buffer.length)) != -1) {
            outstr.write(buffer, 0, size);
          }
          instr.close();
          outstr.flush();
          outstr.close();

          int pageCount = 0;
          try {
              // we create a reader for a certain document
              PdfReader reader = new PdfReader(fullPathFileName);
              // we retrieve the total number of pages
              pageCount = reader.getNumberOfPages();
          }
          catch (Exception e) {
              //e.printStackTrace();
          }

          totalPageCount += pageCount;

          fwFile.write("\n"+acctId + "," + billingPeriod + "," + fileName + "," + pageCount);

          cfgObj.write("Bill Reprint StmtID: " + statementId + ", Account : " + acctId + ", Pages: " + pageCount, APP_NAME);

          DBLog.createReprintDetailRecord(strFileName.substring(pos+1) + ".csv", strActivityId, pageCount);

          if(i==intEndIdx-1){
            fwFile.write("\n" + cfgObj.reprintFooter1 + "," + "" + "," + intEndIdx + "," + totalPageCount);
            DBLog.createReprintRecord(strFileName.substring(pos+1) + ".csv", intEndIdx-intStartIdx);
          }

        }// end for

        if(persisServerCtr != 0) {
          //cfgObj.write("Commiting transaction when ctr !=0.......", APP_NAME);
          PersistServer.commitTransaction();
        }

        fwFile.close();

      }catch (Exception ex) {
        cfgObj.write("Process Name(BillReprintThread)- " + ex.getClass() + " " + ex.getMessage(), APP_NAME);
      }finally {
        if (PersistServer.transactionIsActive()) {
          try {
            PersistServer.rollbackTransaction();
            cfgObj.write("Process Name(BillReprintThread)- Rolling back all CheckFree transactions", APP_NAME);
          }catch (Exception e) {
            //ignore
          }
        }
        PersistServer.deactivate(true); //clean up with deactivate
      }// end try
    }//end run
  }// end class

  public static void printUsage() {
        System.out.println("\nCopyright (c) 2002 FSBM CTech Sdn Bhd (427095-M).");
        System.out.println("All rights reserved.");
        System.out.println("\n\nUsage : billRePrintDeliver.sh");
        System.out.println("or :");
        System.out.println("\tjava -server -Xms[HS] -Xmx[HS] -DBGROOT=[BGROOT] com.fsbm.ctech.maxis.ebpsbackend.BillReprintDeliver -threadcount=[X]");
        System.out.println("\n\nWhere:");
        System.out.println("\t -[HS] Min and Max Heap Memory size allocation");
        System.out.println("\t -[BGROOT] CheckFree installation directory");
        System.out.println("\t -[X] Max thread count");
        System.out.println("\n\tor java com.fsbm.ctech.maxis.ebpsbackend.BillReprintDeliver -h for help options");
        System.out.println("\tor billRePrintDeliver.sh -h for help options");
   }

  public static String getFormattedAmount(String amountDue) {
              amountDue    = amountDue.replace(',',' ');
              StringTokenizer stAmountDue = new StringTokenizer(amountDue," ",false);
              amountDue    = "";
              while (stAmountDue.hasMoreElements()) amountDue += stAmountDue.nextElement();
      return amountDue;
  }


} // end class BillReprintDeliver

